package com.ubix.kiosoft2.utils;

import android.app.Activity;
import android.content.Context;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.location.LocationManager;
import android.util.Base64;
import android.util.Log;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;

/**
 * @Created by Chris on 8/22/2016.
 */
public final class Utils {


    /**
     * Devides byte array by chunk size
     *
     * @param bytes byte array
     * @param chunk size of chunk
     * @return 2 demensional byte array
     */
    public static byte[][] devideBytes(byte[] bytes, int chunk) {
        int lastPacketSize = bytes.length % chunk;
        int packetsToSend = (int) Math.ceil(bytes.length / chunk) + 1;
        byte[][] packets = new byte[packetsToSend][chunk];
        int start = 0;
        for (int i = 0; i < packets.length; i++) {
            packets[i] = Arrays.copyOfRange(bytes, start, start + chunk);
            start += chunk;
        }
        byte[] lastPacket = new byte[lastPacketSize];
//        for(int i = 0;i<lastPacketSize;i++) {
//            lastPacket[i] = packets[packets.length - 1][i];
//        }
        System.arraycopy(packets[packets.length - 1], 0, lastPacket, 0, lastPacketSize);
        packets[packets.length - 1] = lastPacket;

        return packets;
    }


    public static void printByteAsHex(byte[] bytes, String extra) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x ", b));
        }
        System.out.println(extra + ": " + sb.toString());
    }

    /**
     * Converts byte array into hexadecimal string
     *
     * @param bytes byte array
     * @return hexadecimal string
     */
    public static String byteToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x ", b));
        }
        return sb.toString().replace(" ", "");
    }


    /**
     * Converts byte into integer
     *
     * @param b byte
     * @return integer
     */
    public static int byteToInt(byte b) {
        return b & 0xFF;
    }

    public static int twoBytesToInt(byte[] bs) {
        return ((int) bs[0] << 8) | ((int) bs[1] & 0xFF);
    }

    /**
     * Check if location is enabled
     *
     * @return boolean
     */
    public static boolean locationEnabled(Context context) {
        boolean gps_enabled = false;
        LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        // Check if GPS provider is enabled
        try {
            return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * Display location setting request
     *
     * @param context
     * @param activity
     */
    public static void displayLocationSettingRequest(Context context, final Activity activity) {
        GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context)
                .addApi(LocationServices.API).build();
        googleApiClient.connect();

        LocationRequest locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(10000);
        locationRequest.setFastestInterval(10000 / 2);

        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
        builder.setAlwaysShow(true);

        PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
        result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
            @Override
            public void onResult(LocationSettingsResult result) {
                final Status status = result.getStatus();
                switch (status.getStatusCode()) {
                    case LocationSettingsStatusCodes.SUCCESS:
                        Log.i("Location Not Found", "All location settings are satisfied.");
                        break;
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        Log.i("Location Not Found", "Location settings are not satisfied. Show the user a dialog to upgrade location settings ");

                        try {
                            // Show the dialog by calling startResolutionForResult(), and check the result
                            // in onActivityResult().
                            status.startResolutionForResult(activity, Constants.LOCATION_REQUEST_ACTION);
                        } catch (IntentSender.SendIntentException e) {
                            Log.i("Location Not Found", "PendingIntent unable to execute request.");
                        }
                        break;
                    case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                        Log.i("Location Not Found", "Location settings are inadequate, and cannot be fixed here. Dialog not created.");
                        break;
                }
            }
        });
    }

    /**
     * Add data from provided sharedPreference
     *
     * @param sharedPref
     * @param key
     * @param data
     */
    public static void addDataToSharedPref(SharedPreferences sharedPref, String key, String data) {
        if (sharedPref != null) {
            SharedPreferences.Editor editor = sharedPref.edit();
            editor.putString(key, data);
            editor.apply();
        }
    }

    /**
     * Add data from provided sharedPreference
     *
     * @param sharedPref
     * @param key
     * @param data       int
     */
    public static void addDataToSharedPref(SharedPreferences sharedPref, String key, int data) {
        if (sharedPref != null) {
            SharedPreferences.Editor editor = sharedPref.edit();
            editor.putInt(key, data);
            editor.apply();
        }
    }

    /**
     * Add data from provided sharedPreference
     *
     * @param sharedPref
     * @param key
     * @param data       int
     */
    public static void addDataToSharedPref(SharedPreferences sharedPref, String key, boolean data) {
        if (sharedPref != null) {
            SharedPreferences.Editor editor = sharedPref.edit();
            editor.putBoolean(key, data);
            editor.apply();
        }
    }

    /**
     * Remove data from provicded sharedPreference
     *
     * @param sharedPref
     * @param key
     */
    public static void removeDataFromSharedPref(SharedPreferences sharedPref, String key) {
        if (sharedPref != null) {
            SharedPreferences.Editor editor = sharedPref.edit();
            editor.remove(key);
            editor.apply();
        }
    }


    public static void saveObjectToSharedPref(SharedPreferences sharedPref, String key, Object saveObject) {
        if (sharedPref != null) {
            SharedPreferences.Editor editor = sharedPref.edit();
            String string = Object2String(saveObject);
            editor.putString(key, string);
            editor.commit();
        }

    }


    public static Object getObjectFromSharedPref(SharedPreferences sharedPref, String key) {
        if (sharedPref != null) {
            String string = sharedPref.getString(key, null);
            if (string != null) {
                return String2Object(string);
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * writeObject 方法负责写入特定类的对象的状态，以便相应的 readObject 方法可以还原它
     * 最后，用Base64.encode将字节文件转换成Base64编码保存在String中
     *
     * @param object 待加密的转换为String的对象
     * @return String   加密后的String
     */
    private static String Object2String(Object object) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream;
        try {
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            String string = new String(Base64.encode(byteArrayOutputStream.toByteArray(), Base64.DEFAULT));
            objectOutputStream.close();
            return string;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 使用Base64解密String，返回Object对象
     *
     * @param objectString 待解密的String
     * @return object      解密后的object
     */
    private static Object String2Object(String objectString) {
        byte[] mobileBytes = Base64.decode(objectString.getBytes(), Base64.DEFAULT);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(mobileBytes);
        ObjectInputStream objectInputStream;
        try {
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            Object object = objectInputStream.readObject();
            objectInputStream.close();
            return object;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
